
import socket
from collections import deque
import asyncore
import simplejson
import config
import logging

class JSONConnection:
    def __init__(self):
        self._command_sep = "\x00"
        
        self._recv_buffer = deque()
        self._send_buffer = deque()
        
        self._commands = {}
        
    def decode(self, data_received):        
        while True:
            pos = data_received.find(self._command_sep)
            if pos > -1:
                self._recv_buffer.append(data_received[:pos])
                message_s = "".join(self._recv_buffer)
                message_j = simplejson.loads(message_s)
                self.handle_message_received(message_j)
                self._recv_buffer.clear()
                 
                data_received = data_received[pos + len(self._command_sep):]
                
                if not len(data_received):
                    break
            else:
                self._recv_buffer.append(data_received)
                break

        return message_j
        
    def handle_read(self):
        data_received = self.recv(8192)
        if data_received:
            self.decode(data_received)

    def write_json(self, message):
        """
        Sends a JSON message as a null terminated string
        """
        self._send_buffer.append(simplejson.dumps(message) + self._command_sep)
    
    def writable(self):
        """
        Returns true if we have data to write to the socket
        """
        return len(self._send_buffer) > 0
    
    def handle_write(self):
        data_part = self._send_buffer.popleft()
        sent = self.send(data_part) #write on socket
        
        if sent < len(data_part):
            self._send_buffer.appendleft(data_part[sent:])
            
    def handle_message_received(self, message):
        self._commands.get(message["cmd"], self.command_error)(message)
    
    def command_error(self, message):
        try:
            logging.warning("Unknown command received : %s", message["msg"])
        except KeyError:
            logging.warning("Invalid message received : %s", message)
        
class IndexConnection(JSONConnection, asyncore.dispatcher):
    """
    Connects to the index server
    """
    
    def __init__(self):
        JSONConnection.__init__(self)
        asyncore.dispatcher.__init__(self)
        
        self.response_received = False
        #index_response must be specified by inheriting class
        self._commands = {'index_response' : None}
        
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.connect(config.get_index_server())




